package com.llbnk.controller;

import com.alibaba.druid.util.StringUtils;
import com.llbnk.error.BusinessException;
import com.llbnk.error.EmBusinessError;
import com.llbnk.log.LogAction;
import com.llbnk.log.LogGenerator;
import com.llbnk.logpool.LogPoolManager;
import com.llbnk.pojo.dto.ItemVO;
import com.llbnk.pojo.dto.UserVO;
import com.llbnk.pojo.entity.DetailLog;
import com.llbnk.pojo.model.ItemModel;
import com.llbnk.pojo.model.UserModel;
import com.llbnk.response.CommonReturnType;
import com.llbnk.service.UserService;
import com.llbnk.service.impl.ItemServiceImpl;
import com.llbnk.util.RandomUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.web.bind.annotation.*;
import sun.misc.BASE64Encoder;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.io.UnsupportedEncodingException;
import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.UUID;
import java.util.concurrent.TimeUnit;

/**
 * @author shkstart
 * @create 2022-08-19 22:13
 */
@RestController
@CrossOrigin(allowCredentials = "true",allowedHeaders = "*")
@Slf4j
public class UserController extends BaseController{

    //请求头Content-Type  application/x-www-form-urlencoded
    //public static final String CONTENT_TYPE_FORMED="application/x-www-form-urlencoded";

    @Resource
    private UserService userService;

    //HttpServletRequest通过一个bean的模式注入进来，说明这个HttpServletRequest是一个单例模式
    //单例模式怎么支持一个request，支持多个用户线程的并发访问呢？
    //其实这个通过bean包装的HttpServletRequest，他的本质是一个拥有Threadlocal的map，去让用户
    //在每个线程当中去处理自己的对应的request
    @Resource
    private HttpServletRequest httpServletRequest;

    @Resource
    private ItemServiceImpl itemService;

    @Resource
    private RedisTemplate redisTemplate;

    //异步更新日志
    @Resource
    private LogPoolManager logPoolManager;


    @GetMapping(value = "/user/test")
    public void test(){
     userService.test();
    }


    @GetMapping("/user/logtest")
    public void logTest() {
        // 此处可以写具体的业务逻辑

        DetailLog DetailLog = new DetailLog();
        DetailLog.setLogcontent(LogGenerator.getLog(httpServletRequest,"1", LogAction.FIND.getAction(), "登录"));
        // 将业务日志放入到队列中，然后使用线程 异步 批量进行入库，以提升接口的响应速度
        try {
            logPoolManager.addLog(DetailLog);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }

        log.info("log offer queue success !");
    }

    /**专门用于插入异步日志的方法*/
    public void userLog(String userId,String action,String info){
        DetailLog DetailLog = new DetailLog();
        DetailLog.setLogcontent(LogGenerator.getLog(httpServletRequest,userId,action, info));
        // 将业务日志放入到队列中，然后使用线程 异步 批量进行入库，以提升接口的响应速度
        try {
            logPoolManager.addLog(DetailLog);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
        }
    }

    //用户登录接口
    @PostMapping(value = "/user/login", consumes = {CONTENT_TYPE_FORMED})
    public CommonReturnType login(@RequestParam(name = "telephone")String telephone,
                                  @RequestParam(name = "password")String password) throws BusinessException, UnsupportedEncodingException, NoSuchAlgorithmException {
        log.info("telephone:"+telephone+" password: "+password);
        //入参校验
        if(org.apache.commons.lang3.StringUtils.isEmpty(telephone) ||
                org.apache.commons.lang3.StringUtils.isEmpty(password)){
            throw new BusinessException(EmBusinessError.USER_NOT_LOGIN, "请登录后下单");
        }
        //用户登录服务
        UserModel userModel = userService.vaildateLogin(telephone, EncodeByMd5(password));

        //将登录凭证加入到用户登录成功的session内
        //httpServletRequest.getSession().setAttribute("IS_LOGIN", true);
        //httpServletRequest.getSession().setAttribute("LOGIN_USER", userModel);

        //采用redis+UUID的方式生成分布式会话中唯一的token
        String uuidToken = UUID.randomUUID().toString();
        uuidToken = uuidToken.replace("-","");
        redisTemplate.opsForValue().set(uuidToken,userModel);
        redisTemplate.expire(uuidToken,1, TimeUnit.DAYS);

        //插入异步日志
        userLog(userModel.getId()+"",LogAction.FIND.getAction(),"用户登录");

        //下发token
        return CommonReturnType.create(uuidToken);
    }


    private ItemVO convertVOFromModel(ItemModel itemModel) {
        ItemVO itemVO = new ItemVO();
        BeanUtils.copyProperties(itemModel,itemVO);
        return itemVO;
    }

    @PostMapping(value = "/user/register",consumes = CONTENT_TYPE_FORMED)
    public CommonReturnType register(@RequestParam(name = "telephone") String telephone,
                                     @RequestParam(name = "otpCode") String otpCode,
                                     @RequestParam(name = "name") String name, @RequestParam(name = "age") Integer age,
                                     @RequestParam(name = "gender") Byte gender,
                                     @RequestParam(name = "password") String password
                                    ) throws BusinessException, UnsupportedEncodingException, NoSuchAlgorithmException {
        //验证手机号和对应的otpcode相符合
        //第一步从httpSession中拿出otpcode和用户输入的otpcode相比较
        String sessionCode1 = (String) this.httpServletRequest.getSession().getAttribute(telephone);
        String sessionCode = this.httpServletRequest.getParameter("otpCode");
        log.info("从session中获取验证码：" + sessionCode1 +"\t"+sessionCode);
        if(StringUtils.equals(otpCode,sessionCode) != true){
            throw new BusinessException(EmBusinessError.PARAMETER_VALIDATION_ERROR,"验证码不正确，请重试");
        }
        UserModel userModel = new UserModel();
        userModel.setName(name);
        userModel.setGender(new Byte(String.valueOf(gender)));
        userModel.setAge(age);
        userModel.setTelephone(telephone);
        userModel.setRegisterMode("byphone");
        userModel.setEncrptPassword(EncodeByMd5(password));
        userService.register(userModel);

        //插入异步日志
        userLog(null,LogAction.INCREASE.getAction(),"用户注册");

        return CommonReturnType.create("注册成功！");
    }

    public String EncodeByMd5(String str) throws UnsupportedEncodingException, NoSuchAlgorithmException {
        //确定计算方法
        MessageDigest md5 = MessageDigest.getInstance("MD5");
        BASE64Encoder base64Encoder = new BASE64Encoder();
        //加密字符串
        String newstr = base64Encoder.encode(md5.digest(str.getBytes("utf-8")));
        return newstr;
    }

    //post的请求头格式:application/x-www-form-urlencoded
    @PostMapping (value = "/user/getotp",consumes = CONTENT_TYPE_FORMED)
    public CommonReturnType getOtp(@RequestParam(name = "telephone") String telephone){
        //按照一定规律生成OTP验证码
        String optCode = RandomUtils.getSixBitRandom();
        //将OTP验证码对应用户手机号进行关联，正常是使用redis进行一个手机号和验证码的绑定
        //这里这个不是重点使用httpsession进行绑定
        httpServletRequest.getSession().setAttribute(telephone,optCode);
        //将OPT验证码通过短信通道发送给用户，着里就用控制台打印代替
        System.out.println("telephone = "+telephone+" & optCode = "+optCode);

        //插入异步日志
        userLog(null,LogAction.INCREASE.getAction(),"发送验证码");

        return CommonReturnType.create(null);
    }


    @RequestMapping("/user/get/{id}")
    public CommonReturnType getUser(@PathVariable Integer id) throws BusinessException {
        //调用serivce返回全部用户信息包括userinfo中和password
        UserModel userById = userService.getUserById(id);
        if(userById == null) {
            throw new NullPointerException();
            // throw new BusinessException(EmBusinessError.USER_NOT_EXIST);
        }
        //展示给前端以userVO的方式去除多余的敏感信息
        UserVO userVO = convertFromModel(userById);

        //插入异步日志
        userLog(id+"",LogAction.FIND.getAction(),"查询所有用户信息");

        return CommonReturnType.create(userVO);
    }

    private UserVO convertFromModel(UserModel userModel){
        if(userModel == null) return null;
        UserVO userVO = new UserVO();
        BeanUtils.copyProperties(userModel,userVO);
        return userVO;
    }



}
